﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using GameCreator.Core;
using Gp.Scripts.Core.Skill;
using Gp.Scripts.Data;
using Gp.Scripts.Data.Skills;
using Gp.Scripts.Equip;
using Gp.Scripts.GUI;
using Helpers;
using QFramework;
using UnityEngine;
using Object = UnityEngine.Object;

namespace Gp.Scripts.Core
{
    public abstract class SkillEntity : Ability
    {
        public ConfigSkill Config;
        protected List<VBattleCell> CachedTargetCells = new(0);
        protected List<VBattleCell> CachedTargetUnits = new(0);

        protected SkillEntity() { }

        public static T Create<T>(ConfigSkill config) where T : SkillEntity, new()
        {
            return new T() {Config = config};
        }

        public SkillEntity(ConfigSkill config)
        {
            Config = config;
        }


        public void Init(BaseUnit caster)
        {
            this.UnitReference = caster;
            OnInit();
        }

        protected virtual void OnInit() { }

        protected virtual void OnDestroy() { }


        public virtual SkillButtonInfo RenderInfo()
        {
            return new SkillButtonInfo(null, Config.Name, Config.Desc);
        }


        # region Util Function

        protected virtual void OnPreExecute()
        {
            CostResource();
        }

        /// <summary>
        /// 由人类输入执行的技能释放
        /// </summary>
        public DisableReason HumanExecute(SkillContext context)
        {
            var dsReason = CanExecute(context);
            if (!dsReason.Result()) return dsReason;
            // 资源消耗
            OnPreExecute();
            var level = Global.Get<BattleSystem>().BattleSettle;

            level.AddSequenceBuffer("Skill Execute ---->\t" + Config.Name, ExecuteProcess(context));
            return DisableReason.True();
        }

        private IEnumerator ExecuteProcess(SkillContext context)
        {
            var key = new object();
            Global.Get<BattleSystem>().BlockInput(key);

            yield return Act(context);

            Global.Get<BattleSystem>().UnBlockInput(key);
        }


        /// <summary>
        /// 由AI执行的技能释放，会根据技能逻辑职能选择目标
        /// </summary>
        /// <returns></returns>
        public IEnumerator AIExecute()
        {
            return AIExecute(GetAIContext());
        }


        // /// <summary>
        // /// 强制执行，不消耗资源
        // /// </summary>
        // /// <returns></returns>
        // public IEnumerator ForceExecute(SkillContext context) {
        //     yield return Execute(context);
        // }


        public virtual IEnumerator AIExecute(SkillContext context)
        {
            if (!CanSelect().Result(out var reasonId))
            {
                Helpers.LogHelper.LogError($"Skill AIExecute",
                    $"尝试执行不满足使用条件的技能 ({Config.Id})-'{Config.Name}, 无法执行原因：{reasonId.Text()}'");
                yield break;
            }

            OnAbilitySelected();
            OnPreExecute();
            yield return Act(context);
            OnAbilityDeselected();
        }

        protected virtual IEnumerator OnAIExecute(SkillContext context)
        {
            OnPreExecute();
            yield return ExecuteProcess(context);
        }


        /// <summary>
        /// AI目标选择函数。
        /// </summary>
        /// <returns></returns>
        public virtual SkillContext GetAIContext()
        {
            return null;
        }


        /// <summary>
        /// 子类重写
        /// </summary>
        /// <returns>返回技能释放所需的资源</returns>
        public virtual CostWrapper SkillCostInfo()
        {
            return CostWrapper.Empty;
        }


        /// <summary>
        /// 消耗资源
        /// </summary>
        protected void CostResource()
        {
            var costWrapper = SkillCostInfo();

            List<ResourceCost> ls = new();
            if (costWrapper.AllResource)
            {
                foreach (var info in costWrapper.Costs)
                {
                    ls.Add(info);
                    UnitReference.ComCost.ReduceResource(info);
                }
            }
            else
            {
                costWrapper.Costs.Sort((a, b) => a.Type.CostOrder() - b.Type.CostOrder());
                foreach (var info in costWrapper.Costs.Where(info => UnitReference.ComCost.CheckResource(info)))
                {
                    ls.Add(info);
                    UnitReference.ComCost.ReduceResource(info);
                    break;
                }
            }

            // Debug.Log("消耗");
            LogHelper.LogColor($"SKILL {this.Config.Id} -【{this.Config.Name}】", $"消耗： {string.Join("," , ls.Select(x => $"{x.Type} - {x.Amount}"))}", Color.yellow);
            UnitReference.TriggerEvent(new Event_Unit.CostChange());
        }


        /// <summary>
        /// 判断是否有足够行动点发动能力
        /// </summary>
        /// <returns></returns>
        protected bool ResourceJudge()
        {
            // 是否所有资源充足
            var wp = SkillCostInfo();
            return wp.AllResource
                ? wp.Costs.All(info => UnitReference.ComCost.CheckResource(info))
                : wp.Costs.Any(info => UnitReference.ComCost.CheckResource(info));
        }


        /// <summary>
        /// 标记此技能将会消耗的资源
        /// </summary>
        protected void ResourceMark(IEnumerator<ResourceCost> costs) { }


        /// <summary>
        /// 取消技能消耗资源标记
        /// </summary>
        protected void ResourceUnMark() { }


        public static Vector3 GroundPos(BaseUnit unit)
        {
            return unit.transform.position;
        }

        #endregion


        #region State Function

        /// <summary>
        ///  用于显示指示器。函数内逻辑为UI指示逻辑。
        /// </summary>
        public override void Display()
        {
            if (!CanSelect().Result())
                return;
            // 标记技能范围
            Global.SendEvent(new Event_SkillUI.Display(this));
        }


        /// <summary>
        /// 清除指示器。在技能执行时也会调用，以清除技能指示
        /// </summary>
        public override void CleanUp()
        {
            Global.SendEvent(new Event_SkillUI.CleanUp(this));
            // UnMarkCells();
            ResourceUnMark();
        }

        /// <summary>
        /// 在技能选中后调用。与Display的区别是，该函数会在缓冲队列中执行，而Display是在点击后立即执行。该函数用于动画播放和技能预计算
        /// </summary>
        public sealed override void OnAbilitySelected()
        {
            // 缓存技能范围
            CachedTargetCells.Clear();
            CachedTargetCells = CalSkillRange();
        }

        /// <summary>
        /// 在技能取消选中后调用的函数，调用时机为输入缓冲结束后
        /// </summary>
        public override void OnAbilityDeselected()
        {
            CachedTargetCells.Clear();
        }


        /// <summary>
        /// 判断一个技能能否被选中
        /// </summary>
        /// <returns></returns>
        public virtual DisableReason CanSelect()
        {
            return DisableReason.Build(DS_Reason.EMPTY, () => this is not IPassiveAbility)
                    .And(DS_Reason.COST_NOT_ENOUGH, ResourceJudge)
                    .And(BattleLogic.CanSkillPerform(this))
                ;
        }

        /// <summary>
        /// 判断一个技能能否执行
        /// </summary>
        /// <returns></returns>
        public virtual DisableReason CanExecute(SkillContext context)
        {
            return CanSelect().And(DS_Reason.InvalidTarget, () =>
            {
                //TODO YHK: 根据技能类型决定
                return context.TargetCell.IsValid && CalSkillRange().Contains(context.TargetCell);
            });
        }


        public virtual IEnumerator OnTurnStart()
        {
            yield break;
        }

        public virtual IEnumerator OnTurnEnd()
        {
            yield break;
        }


        //TODO YHK：封装到预计算中
        public virtual List<VBattleCell> CalSkillRange()
        {
            return CachedTargetCells;
        }

        #endregion


        #region Task

        protected CoroutineTask Task()
        {
            return new CoroutineTask();
        }

        #endregion
    }


    public class CoroutineTask
    {
        public static CoroutineTask Sequence()
        {
            return new CoroutineTask();
        }


        private class Task
        {
            private readonly Func<IEnumerator> _action;
            public bool Finished;

            public Task(Func<IEnumerator> action, bool finished)
            {
                _action  = action;
                Finished = finished;
            }


            public IEnumerator Execute()
            {
                yield return _action();
                Finished = true;
            }
        }

        private readonly List<Task> _tasks = new();


        public CoroutineTask Add(Func<IEnumerator> action)
        {
            _tasks.Add(new Task(action, false));
            return this;
        }

        public IEnumerator All()
        {
            foreach (var task in _tasks)
            {
                CoroutinesManager.Instance.StartCoroutine(task.Execute());
            }

            while (_tasks.Any(t => !t.Finished))
            {
                yield return null;
            }
        }


        public IEnumerator Any()
        {
            foreach (var task in _tasks)
            {
                CoroutinesManager.Instance.StartCoroutine(task.Execute());
            }

            while (_tasks.All(t => !t.Finished))
            {
                yield return null;
            }
        }
    }
}